package yogaService

import (
	"duoke/model"
	"duoke/model/yogaModel"
	"duoke/service"
	"duoke/service/asynchronous"
	"duoke/utils/gconv"
	"duoke/utils/gjson"
	"duoke/utils/orm"
	"duoke/utils/redislib"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/go-pay/gopay"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/sirupsen/logrus"
	"time"
	"xorm.io/xorm"
)

func (s *orderService) YogaNotify(c *gin.Context, req gopay.BodyMap) error {
	const (
		tableOrder      = "yoga_order"
		tableOrderSub   = "yoga_order_sub"
		tableGroupClass = "yoga_group_class"
		tablesMyOrder   = "yoga_my_order"
	)

	session := orm.Db.NewSession()
	defer func(session *xorm.Session) {
		err := session.Close()
		if err != nil {
			logrus.WithField("order_no", req.GetString("out_trade_no")).Error("关闭事务失败: ", err)
		}
	}(session)

	if err := session.Begin(); err != nil {
		return errors.New("启动事务失败")
	}

	orderNo := req.GetString("out_trade_no")

	// 查询主订单
	var m yogaModel.ReqOrder
	has, err := session.Table(tableOrder).Where("order_no = ?", orderNo).Get(&m)
	if err != nil || !has {
		_ = session.Rollback()
		return errors.New("该订单不存在")
	}

	// 查询课程信息
	var gc yogaModel.ReqGroupClass
	has, err = session.Table(tableGroupClass).Where("id = ?", m.ClassId).Get(&gc)
	if err != nil || !has {
		_ = session.Rollback()
		return errors.New("预定课程不存在")
	}

	// 查询子订单
	var sub yogaModel.ReqOrderSub
	has, err = session.Table(tableOrderSub).Where("order_no = ?", orderNo).Get(&sub)
	if err != nil || !has {
		_ = session.Rollback()
		return errors.New("该订单子表不存在")
	}

	// 查询教练信息
	var t yogaModel.ReqTeacher
	has, err = session.Table("yoga_teacher").Where("id = ?", gc.TeacherId).Get(&t)
	if err != nil || !has {
		_ = session.Rollback()
		return errors.New("教练不存在")
	}

	// 更新订单状态
	update, err := session.Table(tableOrder).
		Where("order_no = ?", orderNo).
		Update(map[string]interface{}{
			"state":          1,
			"pay_time":       gtime.Now().Unix(),
			"transaction_id": req.GetString("transaction_id"),
		})
	if err != nil || update != 1 {
		_ = session.Rollback()
		return errors.New("修改订单失败")
	}

	// 更新课程购买数
	update, err = session.Table(tableGroupClass).
		Where("id = ?", gc.Id).
		Incr("buy_count", 1).
		Update(&gc)
	if err != nil || update != 1 {
		_ = session.Rollback()
		return errors.New("修改课程失败")
	}

	// 插入我的订单记录
	mo := &yogaModel.ReqMyOrder{
		ClassId:           gc.Id,
		ClassType:         gc.ClassType,
		Cover:             gc.Cover,
		OrderNo:           orderNo,
		Title:             gc.Name,
		Content:           gc.Content,
		TotalAmount:       sub.Price,
		Teacher:           t.Name,
		UserId:            m.UserId,
		OrderType:         1,
		SignType:          2,
		AppointmentStatus: 2,
		StartTime:         gc.StartTime,
		EndTime:           gc.EndTime,
		SubMchId:          gc.SubMchId,
	}
	insert, err := session.Table(tablesMyOrder).Insert(mo)
	if err != nil || insert != 1 {
		_ = session.Rollback()
		return errors.New("插入失败")
	}

	// 提交事务
	if err = session.Commit(); err != nil {
		return errors.New("提交事务失败")
	}

	// 异步处理（不阻塞主流程）
	go func(orderNo string) {
		// 提取所需参数，避免使用 c *gin.Context
		subMchID := req.GetString("sub_mch_id")
		subOpenID := req.GetString("sub_openid")
		mchID := req.GetString("mch_id")
		openID := req.GetString("openid")
		totalFee := gconv.Float64(req.GetString("total_fee"))
		transactionID := req.GetString("transaction_id")

		stream, err := redislib.NewRedisStream(redislib.Redis,
			"notifications_stream", "notifications_group", "consumer_1")
		if err != nil {
			logrus.WithField("order_no", orderNo).Warn("初始化 Redis Stream 失败: ", err)
			return
		}
		separateService := asynchronous.NewSeparateService(stream)
		go func() {
			defer func() {
				if r := recover(); r != nil {
					logrus.WithField("order_no", orderNo).Error("异步监听 panic:", r)
				}
			}()
			separateService.StartListening(c)
		}()

		time.AfterFunc(2*time.Second, func() {
			defer func() {
				if r := recover(); r != nil {
					logrus.WithField("order_no", orderNo).Error("异步任务 panic:", r)
				}
			}()

			// 绑定分账用户
			message := map[string]interface{}{
				"type": "bind_user",
				"content": gjson.StructOrMap2Json(&model.ReqSubAccount{
					SubMchId:         subMchID,
					ReceivierType:    "PERSONAL_OPENID",
					ReceivierAccount: subOpenID,
				}),
			}
			separateService.SendNotification(message)

			// 分账
			message = map[string]interface{}{
				"type": "separate_accounts",
				"content": gjson.StructOrMap2Json(&model.SeparateApply{
					MchId:         mchID,
					SubMchId:      subMchID,
					OutTradeNo:    orderNo,
					TotalFee:      totalFee,
					Openid:        openID,
					TransactionId: transactionID,
				}),
			}
			separateService.SendNotification(message)
		})

		// 异步处理积分相关逻辑（可选）
		userID := m.UserId
		giftPoints := gc.GiftPoints
		integral := sub.Integral
		couponID := sub.CouponId

		if giftPoints > 0 {
			go func() {
				err := service.User.Score(c, userID, giftPoints, "预约课程赠送积分")
				if err != nil {
					logrus.WithFields(logrus.Fields{
						"order_no": orderNo,
						"user_id":  userID,
					}).Error("赠送积分失败: ", err)
				}
			}()
		}

		if integral > 0 {
			go func() {
				err := service.User.Score(c, userID, -integral, "预约扣除积分")
				if err != nil {
					logrus.WithFields(logrus.Fields{
						"order_no": orderNo,
						"user_id":  userID,
					}).Error("扣除积分失败: ", err)
				}
			}()
		}

		if couponID > 0 {
			go func() {
				err := service.Coupon.Use(c, couponID)
				if err != nil {
					logrus.WithFields(logrus.Fields{
						"order_no":  orderNo,
						"coupon_id": couponID,
					}).Error("优惠券使用失败: ", err)
				}
			}()
		}
	}(orderNo)

	return nil
}
func (s *orderService) YogaCourseNotify(c *gin.Context, req gopay.BodyMap) error {
	const (
		tableOrder     = "yoga_course_order"
		tableOrderSub  = "yoga_order_sub"
		tableCourse    = "yoga_course"
		tablesMyCourse = "yoga_my_course"
	)

	session := orm.Db.NewSession()
	defer func(session *xorm.Session) {
		err := session.Close()
		if err != nil {
			logrus.WithField("order_no", req.GetString("out_trade_no")).Error("关闭事务失败: ", err)
		}
	}(session)

	if err := session.Begin(); err != nil {
		return errors.New("启动事务失败")
	}

	orderNo := req.GetString("out_trade_no")

	// 查询主订单
	var m yogaModel.ReqCourseOrder
	has, err := session.Table(tableOrder).Where("order_no = ?", orderNo).Get(&m)
	if err != nil || !has {
		_ = session.Rollback()
		return errors.New("该订单不存在")
	}

	// 查询课程信息
	var gc yogaModel.ReqCourse
	has, err = session.Table(tableCourse).Where("id = ?", m.FromId).Get(&gc)
	if err != nil || !has {
		_ = session.Rollback()
		return errors.New("预定课程不存在")
	}

	// 查询子订单
	var sub yogaModel.ReqOrderSub
	has, err = session.Table(tableOrderSub).Where("order_no = ?", orderNo).Get(&sub)
	if err != nil || !has {
		_ = session.Rollback()
		return errors.New("该订单子表不存在")
	}
	// 更新订单状态
	update, err := session.Table(tableOrder).
		Where("order_no = ?", orderNo).
		Update(map[string]interface{}{
			"state":          1,
			"pay_time":       gtime.Now().Unix(),
			"transaction_id": req.GetString("transaction_id"),
		})
	if err != nil || update != 1 {
		_ = session.Rollback()
		return errors.New("修改订单失败")
	}

	// 更新课程购买数
	update, err = session.Table(tableCourse).
		Where("id = ?", gc.Id).
		Incr("buy_count", 1).
		Update(&gc)
	if err != nil || update != 1 {
		_ = session.Rollback()
		return errors.New("修改课程失败")
	}

	// 插入我的订单记录
	mo := &yogaModel.ReqMyCourse{
		ClassId:           gc.Id,
		Cover:             gc.Cover,
		OrderNo:           orderNo,
		Title:             gc.Name,
		Content:           gc.Describe,
		TotalAmount:       sub.Price,
		UserId:            m.UserId,
		SignType:          2,
		AppointmentStatus: 2,
		StartTime:         gc.StartTime,
		EndTime:           gc.EndTime,
		SubMchId:          gc.SubMchId,
	}
	insert, err := session.Table(tablesMyCourse).Insert(mo)
	if err != nil || insert != 1 {
		_ = session.Rollback()
		return errors.New("插入失败")
	}

	// 提交事务
	if err = session.Commit(); err != nil {
		return errors.New("提交事务失败")
	}

	// 异步处理（不阻塞主流程）
	go func(orderNo string) {
		// 提取所需参数，避免使用 c *gin.Context
		subMchID := req.GetString("sub_mch_id")
		subOpenID := req.GetString("sub_openid")
		mchID := req.GetString("mch_id")
		openID := req.GetString("openid")
		totalFee := gconv.Float64(req.GetString("total_fee"))
		transactionID := req.GetString("transaction_id")

		stream, err := redislib.NewRedisStream(redislib.Redis,
			"notifications_stream", "notifications_group", "consumer_1")
		if err != nil {
			logrus.WithField("order_no", orderNo).Warn("初始化 Redis Stream 失败: ", err)
			return
		}
		separateService := asynchronous.NewSeparateService(stream)
		go func() {
			defer func() {
				if r := recover(); r != nil {
					logrus.WithField("order_no", orderNo).Error("异步监听 panic:", r)
				}
			}()
			separateService.StartListening(c)
		}()

		time.AfterFunc(2*time.Second, func() {
			defer func() {
				if r := recover(); r != nil {
					logrus.WithField("order_no", orderNo).Error("异步任务 panic:", r)
				}
			}()

			// 绑定分账用户
			message := map[string]interface{}{
				"type": "bind_user",
				"content": gjson.StructOrMap2Json(&model.ReqSubAccount{
					SubMchId:         subMchID,
					ReceivierType:    "PERSONAL_OPENID",
					ReceivierAccount: subOpenID,
				}),
			}
			separateService.SendNotification(message)

			// 分账
			message = map[string]interface{}{
				"type": "separate_accounts",
				"content": gjson.StructOrMap2Json(&model.SeparateApply{
					MchId:         mchID,
					SubMchId:      subMchID,
					OutTradeNo:    orderNo,
					TotalFee:      totalFee,
					Openid:        openID,
					TransactionId: transactionID,
				}),
			}
			separateService.SendNotification(message)
		})

		// 异步处理积分相关逻辑（可选）
		userID := m.UserId
		giftPoints := gc.GiftPoints
		integral := sub.Integral
		couponID := sub.CouponId

		if giftPoints > 0 {
			go func() {
				err := service.User.Score(c, userID, giftPoints, "预约课程赠送积分")
				if err != nil {
					logrus.WithFields(logrus.Fields{
						"order_no": orderNo,
						"user_id":  userID,
					}).Error("赠送积分失败: ", err)
				}
			}()
		}

		if integral > 0 {
			go func() {
				err := service.User.Score(c, userID, -integral, "预约扣除积分")
				if err != nil {
					logrus.WithFields(logrus.Fields{
						"order_no": orderNo,
						"user_id":  userID,
					}).Error("扣除积分失败: ", err)
				}
			}()
		}

		if couponID > 0 {
			go func() {
				err := service.Coupon.Use(c, couponID)
				if err != nil {
					logrus.WithFields(logrus.Fields{
						"order_no":  orderNo,
						"coupon_id": couponID,
					}).Error("优惠券使用失败: ", err)
				}
			}()
		}
	}(orderNo)

	return nil
}
